﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Othello_Game;

namespace OneOnOneRunnerConsole
{
    class Play
    {
        /// <summary>
        /// Used to store the weights of two computer players playing against each other
        /// </summary>
        public WeightVector Player1Weights, Player2Weights;

        /// <summary>
        /// Used to run games between two computer opponents
        /// </summary>
        public MinMaxTreeSearch MMTS = new MinMaxTreeSearch();

        /// <summary>
        /// How many games each pair of weightVectors play
        /// </summary>
        private int gamesPerPair = 20;

        /// <summary>
        /// Play a game between two computer players
        /// </summary>
        /// <param name="P1W">
        /// Weights of player 1
        /// </param>
        /// <param name="P2W">
        /// Weights of player 2
        /// </param>
        /// <param name="reversePlayerOrder">
        /// States which player plays first (false-->player 1 goes first, true-->player 2 goes first)
        /// </param>
        public int PlayAGame(WeightVector P1W, WeightVector P2W, bool reversePlayerOrder)
        {
            //set players weights
            if (reversePlayerOrder)
            {
                IO.WriteLine("Player " + 2 + " starts", IO.WriteTo.Console);
                this.Player1Weights = P1W;
                this.Player2Weights = P2W;

            }
            else
            {
                IO.WriteLine("Player " + 1 + " starts", IO.WriteTo.Console);
                this.Player1Weights = P2W;
                this.Player2Weights = P1W;
            }

            //initialize the board
            Board board = new Board(8, 8);

            //play a game
            for (int i = 0; i < 60; i++)
            {
                int turn = (i % 2) + 1;
                if (turn == 1) GeneralConsts.Instance.AttributeWeights = Player1Weights;
                else GeneralConsts.Instance.AttributeWeights = Player2Weights;
                ActionList toDo = MMTS.FindBest(board, 3);
                if (toDo != null)
                {
                    board.Play(toDo);
                }
                board.SwitchPlayers();
            }

            int p1count = 0;
            int p2count = 0;

            //Check for and anounce the winner
            for (int row = 0; row < 8; row++)
            {
                for (int col = 0; col < 8; col++)
                {
                    if (board.GetPlayer(new Position(row, col)) == players.PLAYER1) p1count++;
                    else if (board.GetPlayer(new Position(row, col)) == players.PLAYER2) p2count++;
                }
            }
            if (reversePlayerOrder)
            {
                if (p1count > p2count) return 2;
                else if (p2count > p1count) return 1;
                return 0;
            }
            else
            {
                if (p1count > p2count) return 1;
                else if (p2count > p1count) return 2;
                return 0;
            }
        }

        /// <summary>
        /// play a set of games between two cimputer players
        /// </summary>
        /// <param name="howManyGames">
        /// How many games to play
        /// </param>
        /// <param name="P1W">
        /// player 1 weights
        /// </param>
        /// <param name="P2W">
        /// player 2 weights
        /// </param>
        public int playGames(int howManyGames, WeightVector P1W, WeightVector P2W)
        {
            //print out each player weights
            IO.WriteLine("Player1Weights:", IO.WriteTo.ConsoleAndFile);
            for (int i = 0; i < P1W.Count(); i++)
            {
                IO.Write(P1W.at(i) + " ", IO.WriteTo.ConsoleAndFile);
            }
            IO.WriteLine("", IO.WriteTo.ConsoleAndFile);

            IO.WriteLine("Player2Weights:", IO.WriteTo.ConsoleAndFile);
            for (int i = 0; i < P2W.Count(); i++)
            {
                IO.Write(P2W.at(i) + " ", IO.WriteTo.ConsoleAndFile);
            }
            IO.WriteLine("", IO.WriteTo.ConsoleAndFile);

            Play play = new Play();
            int p1wins = 0;
            int p2wins = 0;
            int result = 0;

            //play all games
            for (int i = 0; i < howManyGames; i++)
            {
                IO.WriteLine("Game " + (i+1), IO.WriteTo.Console);
                
                //if half of the games have already been played player 2 should go first
                bool reversePlayers = (i >= (howManyGames / 2));
                result = play.PlayAGame(P1W, P2W, reversePlayers);
                if (result == 1) p1wins++;
                else if (result == 2) p2wins++;
            }

            //anounce results
            IO.WriteLine("Player 1 won " + p1wins + " games", IO.WriteTo.ConsoleAndFile);
            IO.WriteLine("Player 2 won " + p2wins + " games", IO.WriteTo.ConsoleAndFile);
            IO.WriteLine("", IO.WriteTo.ConsoleAndFile);

            //return who won more games
            if (p1wins > p2wins) return 1;
            else if (p2wins > p1wins) return 2;
            return 0;
        }

        /// <summary>
        /// Find best vector in each group (top 5) and run a sequence of games between each pair of weights from the top 5
        /// to find the best Weight vectors to be used in the game
        /// </summary>
        public void FindBestWeights()
        {
            //Hold the winner of each group
            WeightVector[] top5 = playAllGroups();

            IO.WriteLine("Final Tests:", IO.WriteTo.ConsoleAndFile);

            int[] top5results = new int[5];
            for (int i = 0; i < 5; i++)
            {
                top5results[i] = 0;
            }

            //Run a sequence of games between each possible pair of the top 5 vectors
            for (int i = 0; i < 5; i++)
            {
                for (int j = i + 1; j < 5; j++)
                {
                    int winner = playGames(gamesPerPair, top5[i], top5[j]);
                    if (winner == 1) top5results[i]++;
                    else if (winner == 2) top5results[j]++;
                }
            }

            //anounce results
            for (int i = 0; i < 5; i++)
            {
                IO.Write("Weights: ", IO.WriteTo.ConsoleAndFile);
                for (int j = 0; j < 5; j++)
                {
                    IO.Write(top5[i].at(j) + " ", IO.WriteTo.ConsoleAndFile);
                }
                IO.WriteLine(" won " + top5results[i] + "times", IO.WriteTo.ConsoleAndFile);
            }
        }

        /// <summary>
        /// Run tests on all 5 groups an anounce the winner in each group
        /// </summary>
        public WeightVector[] playAllGroups()
        {
            int[,] wins = new int[5,5];
            for (int i=0; i<5; i++)
            {
                for (int j=0; j<5; j++)
                {
                    wins[i,j]=0;
                }
            }

            //Create weight vector groups
            WeightLists WL = new WeightLists();

            //Run a sequence of games on each poossible pair in each group
            for (int i = 0; i < 5; i++)
            {
                IO.WriteLine("Group " + (i + 1), IO.WriteTo.ConsoleAndFile);
                for (int j = 0; j < 5; j++)
                {
                    for (int k = j + 1; k < 5; k++)
                    {
                        int winner = playGames(gamesPerPair, WL.Groups[i, j], WL.Groups[i, k]);
                        if (winner == 1) wins[i, j]++;
                        else if (winner == 2) wins[i, k]++;
                    }
                }
            }

            //Create an fill an array of the best vector in each group
            WeightVector[] top5 = new WeightVector[5];

            for (int i = 0; i < 5; i++)
            {
                int winner = 0;
                int winnerValue = wins[i,0];
                for (int j = 1; j < 5; j++)
                {
                    if (wins[i, j] > winnerValue)
                    {
                        winnerValue = wins[i, j];
                        winner = j;
                    }
                }
                top5[i] = WL.Groups[i, winner];
            }
            return top5;
        }

    }
}
